﻿// 这段 MFC 示例源代码演示如何使用 MFC Microsoft Office Fluent 用户界面
// (“Fluent UI”)。该示例仅供参考，
// 用以补充《Microsoft 基础类参考》和
// MFC C++ 库软件随附的相关电子文档。
// 复制、使用或分发 Fluent UI 的许可条款是单独提供的。
// 若要了解有关 Fluent UI 许可计划的详细信息，请访问
// https://go.microsoft.com/fwlink/?LinkId=238214.
//
// 版权所有(C) Microsoft Corporation
// 保留所有权利。

// MFCPaintView.cpp: CMFCPaintView 类的实现
//

#include "pch.h"
#include "framework.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义，并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFCPaint.h"
#endif

#include "MFCPaintDoc.h"
#include "MFCPaintView.h"
#include "MainFrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CMFCPaintView

IMPLEMENT_DYNCREATE(CMFCPaintView, CFormView)

BEGIN_MESSAGE_MAP(CMFCPaintView, CFormView)
	// 标准打印命令
	ON_COMMAND(ID_FILE_PRINT, &CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCPaintView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_COMMAND(ID_PEN, &CMFCPaintView::OnPen)
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_COMMAND(ID_DUSTBIN, &CMFCPaintView::OnDustbin)
	ON_COMMAND(ID_LINE, &CMFCPaintView::OnLine)
	ON_COMMAND(ID_RECTANGLE, &CMFCPaintView::OnRectangle)
	ON_COMMAND(ID_TRIANGLE, &CMFCPaintView::OnTriangle)
	ON_COMMAND(ID_EDIT_UNDO, &CMFCPaintView::OnCancel)
	ON_COMMAND(ID_EDIT_REDO, &CMFCPaintView::OnRedo)
	ON_COMMAND(ID_SIZE, &CMFCPaintView::OnSize)
	ON_COMMAND(ID_BORDERCOLOR, &CMFCPaintView::OnBordercolor)
	ON_COMMAND(ID_FILLCOLOR, &CMFCPaintView::OnFillcolor)
	ON_COMMAND(ID_SAVEVIEW, &CMFCPaintView::OnSaveView)
END_MESSAGE_MAP()

// CMFCPaintView 构造/析构

CMFCPaintView::CMFCPaintView() noexcept
	: CFormView(IDD_MFCPAINT_FORM)
{
	// TODO: 在此处添加构造代码
	m_bDrawing = false;
	m_CurrentType = DrawingType::NONE;
	//m_EraserSize = 20;
	//m_bErasing = false;
	m_nPenWidth = 1;
	m_PenColor = RGB(0, 0, 0);
	m_cachedPenColor = RGB(0, 0, 0);
	m_BrushColor = RGB(255, 255, 255);
	m_cachedPenWidth = -1;
}

CMFCPaintView::~CMFCPaintView()
{
}

void CMFCPaintView::DoDataExchange(CDataExchange* pDX)
{
	CFormView::DoDataExchange(pDX);
}

BOOL CMFCPaintView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: 在此处通过修改
	//  CREATESTRUCT cs 来修改窗口类或样式

	return CFormView::PreCreateWindow(cs);
}

void CMFCPaintView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();

}


// CMFCPaintView 打印



void CMFCPaintView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CMFCPaintView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 默认准备
	return DoPreparePrinting(pInfo);
}

void CMFCPaintView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加额外的打印前进行的初始化过程
}

void CMFCPaintView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: 添加打印后进行的清理过程
}

void CMFCPaintView::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
	// TODO: 在此处添加自定义打印代码
}

void CMFCPaintView::OnDraw(CDC* pDC)
{
	// 双缓冲技术
	// 创建内存DC和位图
	CDC memDC;
	memDC.CreateCompatibleDC(pDC);
	CBitmap bitmap;
	CRect rect;
	GetClientRect(&rect);
	bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
	CBitmap* pOldBitmap = memDC.SelectObject(&bitmap);
	memDC.FillSolidRect(&rect, RGB(255, 255, 255)); // 背景填充为白色


	// 在内存DC上绘制所有保存的操作
	for (const auto& op : m_Drawings)
	{
		// 当前画笔宽度或者颜色与旧画笔不一致时更新画笔
		if (m_cachedPenWidth != op.penWidth || m_cachedPenColor != op.penColor)
		{
			m_cachedPen.DeleteObject();
			m_cachedPen.CreatePen(PS_SOLID, op.penWidth, op.penColor);
			m_cachedPenWidth = op.penWidth;
			m_cachedPenColor = op.penColor;
		}
		CPen* pOldPen = memDC.SelectObject(&m_cachedPen);

		CBrush* pOldBrush = nullptr;

		switch (op.type)
		{
			case DrawingType::PEN:
			{
				for (size_t i = 1; i < op.points.size(); i++)
				{
					memDC.MoveTo(op.points[i - 1]);
					memDC.LineTo(op.points[i]);
				}
			}
			break;

			case DrawingType::LINE:
			{
				if (op.points.size() >= 2)
				{
					memDC.MoveTo(op.points[0]);
					memDC.LineTo(op.points.back());
				}
			}
			break;

			case DrawingType::RECTANGLE:
			{
				m_cachedBrush.DeleteObject();
				m_cachedBrush.CreateSolidBrush(op.brushColor);
				pOldBrush = memDC.SelectObject(&m_cachedBrush);
				if (op.points.size() >= 2)
				{
					// 终点位置应该为points最后一位
					CRect rect(op.points[0], op.points.back());
					memDC.Rectangle(&rect);
				}
			}
			break;

			case DrawingType::TRIANGLE:
			{
				m_cachedBrush.DeleteObject();
				m_cachedBrush.CreateSolidBrush(op.brushColor);
				pOldBrush = memDC.SelectObject(&m_cachedBrush);
				if (op.points.size() >= 2)
				{
					CPoint p1 = op.points[0]; // 起点
					CPoint p2 = op.points.back(); // 终点，应该是数组最后一位

					// 为垂直的直角，所以直角的点应该是纵坐标与起点相同，横坐标与终点相同
					CPoint p3(p2.x, p1.y);

					// 构造三角形的三个点
					CPoint points[3] = { p1,p3,p2 };
					memDC.Polygon(points, 3);
				}
			}
			break;
		}
		memDC.SelectObject(pOldPen);
		if (pOldBrush)
			memDC.SelectObject(pOldBrush);
	}

	if (m_bDrawing && !m_CurrentPoints.empty())
	{
		// 当前画笔宽度或者颜色与旧画笔不一致时更新画笔
		if (m_cachedPenWidth != m_nPenWidth || m_cachedPenColor != m_PenColor)
		{
			m_cachedPen.DeleteObject();
			m_cachedPen.CreatePen(PS_SOLID, m_nPenWidth, m_PenColor);
			m_cachedPenWidth = m_nPenWidth;
			m_cachedPenColor = m_PenColor;
		}
		CPen* pOldPen = memDC.SelectObject(&m_cachedPen);

		CBrush* pOldBrush = nullptr;

		switch (m_CurrentType)
		{
		case DrawingType::PEN:
			for (size_t i = 1; i < m_CurrentPoints.size(); ++i)
			{
				memDC.MoveTo(m_CurrentPoints[i - 1]);
				memDC.LineTo(m_CurrentPoints[i]);
			}
			break;

		case DrawingType::LINE:
			if (m_CurrentPoints.size() >= 2)
			{
				memDC.MoveTo(m_CurrentPoints[0]);
				memDC.LineTo(m_CurrentPoints.back());
			}
			break;


		case DrawingType::RECTANGLE:
			{
				m_cachedBrush.DeleteObject();
				m_cachedBrush.CreateSolidBrush(m_BrushColor);
				pOldBrush = memDC.SelectObject(&m_cachedBrush);
				if (m_CurrentPoints.size() >= 2)
				{
					CRect rect(m_CurrentPoints[0], m_CurrentPoints.back());
					memDC.Rectangle(&rect);
				}
			}
			break;

		case DrawingType::TRIANGLE:
			{
				m_cachedBrush.DeleteObject();
				m_cachedBrush.CreateSolidBrush(m_BrushColor);
				pOldBrush = memDC.SelectObject(&m_cachedBrush);
				if (m_CurrentPoints.size() >= 2)
				{
					CPoint p1 = m_CurrentPoints[0];
					CPoint p2 = m_CurrentPoints.back();
					CPoint p3(p2.x, p1.y);
					CPoint points[3] = { p1, p3, p2 };
					memDC.Polygon(points, 3);
				}
			}
			break;
		}
		memDC.SelectObject(pOldPen);
		memDC.SelectObject(pOldBrush);
		m_cachedBrush.DeleteObject();
	}

	// 将内存DC内容复制到屏幕
	pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
	memDC.SelectObject(pOldBitmap);
}

void CMFCPaintView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CMFCPaintView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}


// CMFCPaintView 诊断

#ifdef _DEBUG
void CMFCPaintView::AssertValid() const
{
	CFormView::AssertValid();
}

void CMFCPaintView::Dump(CDumpContext& dc) const
{
	CFormView::Dump(dc);
}



CMFCPaintDoc* CMFCPaintView::GetDocument() const // 非调试版本是内联的
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCPaintDoc)));
	return (CMFCPaintDoc*)m_pDocument;
}
#endif //_DEBUG



void CMFCPaintView::SetPenWidth(int nWidth)
{
	m_nPenWidth = nWidth;
}

void CMFCPaintView::SetFrameStatusText(CString name)
{
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

	pFrame->SetStatusBarInfor(name);

}

// CMFCPaintView 消息处理程序


void CMFCPaintView::OnPen()
{
	// TODO: 在此添加命令处理程序代码

	m_CurrentType = DrawingType::PEN;
	SetFrameStatusText("画笔");
}


void CMFCPaintView::OnLButtonDown(UINT nFlags, CPoint point)
{
	/*if (m_CurrentType == DrawingType::RUBBER)
	{
		m_bErasing = true;
		EraseAtPoint(point);
	}
	else
	{
		m_bDrawing = true;
		m_CurrentPoints.clear();    // 清除当前点
		m_CurrentPoints.push_back(point);
	}*/

	m_bDrawing = true;
	m_CurrentPoints.clear();    // 清除当前点
	m_CurrentPoints.push_back(point);
	SetCapture();
	
	// 如果这是第一次绘制操作，将当前（空白）状态保存到撤销栈
	if (m_UndoStack.empty())
	{
		m_UndoStack.push(m_Drawings);
	}
}


void CMFCPaintView::OnLButtonUp(UINT nFlags, CPoint point)
{
	/*if (m_CurrentType == DrawingType::RUBBER)
	{
		m_bErasing = false;
	}*/
	if (m_bDrawing)
	{
		m_CurrentPoints.push_back(point);
		m_bDrawing = false;

		// 保存当前绘图操作，方便后续撤回功能
		DrawingOperation op;
		op.type = m_CurrentType;
		op.points = m_CurrentPoints;
		op.penWidth = m_nPenWidth; // 保存当前画笔宽度
		op.penColor = m_PenColor; // 保存当前画笔颜色
		op.brushColor = m_BrushColor; // 保存当前画刷颜色
		m_Drawings.push_back(op);

		// 将当前绘图操作保存到撤销栈中
		m_UndoStack.push(m_Drawings);

		ReleaseCapture();
		Invalidate();  // 触发重绘
	}
}


void CMFCPaintView::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	if (m_bDrawing && (nFlags & MK_LBUTTON) != 0)
	{
		m_CurrentPoints.push_back(point);
		Invalidate(FALSE);  // 只更新部分窗口
	}
}


void CMFCPaintView::OnDustbin()
{
	// TODO: 在此添加命令处理程序代码
	// 清空操作

	DrawingOperation op;
	m_Drawings.push_back(op);

	// 将当前绘图操作保存到撤销栈中
	m_UndoStack.push(m_Drawings);

	m_Drawings.clear();

	// 重新绘制视图
	Invalidate();
}



void CMFCPaintView::OnLine()
{
	// TODO: 在此添加命令处理程序代码

	m_CurrentType = DrawingType::LINE;
	SetFrameStatusText("直线");
}


void CMFCPaintView::OnRectangle()
{
	// TODO: 在此添加命令处理程序代码

	m_CurrentType = DrawingType::RECTANGLE;
	SetFrameStatusText("矩形");
}


void CMFCPaintView::OnTriangle()
{
	// TODO: 在此添加命令处理程序代码

	m_CurrentType = DrawingType::TRIANGLE;
	SetFrameStatusText("三角形");
}


void CMFCPaintView::OnCancel()
{
	// TODO: 在此添加命令处理程序代码
	// 撤销功能

	if (!m_UndoStack.empty())
	{
		// 将当前绘图状态恢复为上一次的状态
		// 因为当前栈顶为最后一次操作，如果直接使用则不会有任何改变，应该先弹出
		m_doStack.push(m_UndoStack.top());
		m_UndoStack.pop();
		if (m_UndoStack.empty()) return;
		m_Drawings = m_UndoStack.top();

		// 重新绘制视图
		Invalidate();
	}
}


void CMFCPaintView::OnRedo()
{
	// TODO: 在此添加命令处理程序代码

	if (!m_doStack.empty())
	{
		m_UndoStack.push(m_doStack.top());
		m_Drawings = m_doStack.top();
		m_doStack.pop();

		// 重新绘制视图
		Invalidate();
	}
}


void CMFCPaintView::OnSize()
{
	// TODO: 在此添加命令处理程序代码

	// 获取主框架对象
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	// 获取当前RibbonBar
	CMFCRibbonBar* m_wndRibbonBar = pFrame->GetRibbonBar();
	if (m_wndRibbonBar)
	{
		// 获取当前数字编辑器
		CMFCRibbonEdit* pEdit = DYNAMIC_DOWNCAST(CMFCRibbonEdit,m_wndRibbonBar->FindByID(ID_SIZE) );
		if (pEdit)
		{
			// 获取数字编辑器当前值
			CString a = pEdit->GetEditText();
			m_nPenWidth = _ttoi(a);
		}
	}
}


void CMFCPaintView::OnBordercolor()
{
	// TODO: 在此添加命令处理程序代码

	// 获取主框架对象
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	// 获取当前RibbonBar
	CMFCRibbonBar* m_wndRibbonBar = pFrame->GetRibbonBar();
	if (m_wndRibbonBar)
	{
		CMFCRibbonColorButton* borderColor = DYNAMIC_DOWNCAST(CMFCRibbonColorButton, m_wndRibbonBar->FindByID(ID_BORDERCOLOR));
		m_PenColor = borderColor->GetColor();	
	}
}


void CMFCPaintView::OnFillcolor()
{
	// TODO: 在此添加命令处理程序代码

	// 获取主框架对象
	CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();
	// 获取当前RibbonBar
	CMFCRibbonBar* m_wndRibbonBar = pFrame->GetRibbonBar();
	if (m_wndRibbonBar)
	{
		CMFCRibbonColorButton* borderColor = DYNAMIC_DOWNCAST(CMFCRibbonColorButton, m_wndRibbonBar->FindByID(ID_FILLCOLOR));
		m_BrushColor = borderColor->GetColor();
	}
}


void CMFCPaintView::OnSaveView()
{
	// TODO: 在此添加命令处理程序代码

		// 获取视图设备上下文
	CClientDC dc(this);
	CRect rect;
	GetClientRect(&rect);

	// 创建兼容的位图和设备上下文
	HBITMAP hbitmap = CreateCompatibleBitmap(dc, rect.right - rect.left, rect.bottom - rect.top);
	HDC hdc = CreateCompatibleDC(dc);
	HBITMAP hOldMap = (HBITMAP)SelectObject(hdc, hbitmap);

	// 将视图内容复制到新设备上下文
	BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dc, 0, 0, SRCCOPY);

	// 将位图附加到 CImage 对象
	CImage image;
	image.Attach(hbitmap);

	// 弹出文件保存对话框
	CString strFilter = _T("位图文件(*.bmp)|*.bmp|JPEG 图像文件(*.jpg)|*.jpg|PNG 图像文件(*.png)|*.png|所有文件(*.*)|*.*||");
	CFileDialog dlg(FALSE, _T("bmp"), _T("iPaint1.bmp"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, strFilter);
	CString saveFilePath;
	BOOL saveTag = FALSE;
	BOOL showMsgTag = FALSE;

	if (dlg.DoModal() == IDOK) {
		saveTag = TRUE;
		showMsgTag = TRUE;
		saveFilePath = dlg.GetPathName();
		CString strExtension = dlg.GetFileExt();

		// 自动添加扩展名
		if (strExtension.IsEmpty()) {
			switch (dlg.m_ofn.nFilterIndex) {
			case 1: strExtension = _T("bmp"); break;
			case 2: strExtension = _T("jpg"); break;
			case 3: strExtension = _T("png"); break;
			default: strExtension = _T("bmp"); break;
			}
			saveFilePath += _T(".") + strExtension;
		}
	}

	// 保存图像文件
	if (saveTag) {
		HRESULT hResult = image.Save(saveFilePath);
		if (FAILED(hResult)) {
			MessageBox(_T("保存图像文件失败！"));
		}
		else {
			if (showMsgTag) {
				MessageBox(_T("文件保存成功！"));
			}
		}
	}

	// 释放资源
	image.Detach();
	SelectObject(hdc, hOldMap);
	DeleteObject(hbitmap);
	DeleteDC(hdc);
}
